#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <sys/wait.h>
#include <sys/types.h>
#include <vector>
#include <cassert>
#include <ctime>
#include "Task.hpp"

//进程数
#define PROCESS_NUM 5
using namespace std;

//等待写入命令，再读取，返回读取的命令（把八字节变为四字节）
int WaitCommand(int waitid,bool& quit)
{
    uint32_t command = 0;
    //read这里阻塞
    ssize_t n = read(waitid,&command,sizeof(uint32_t));
    //没东西读的时候
    if(n == 0)
    {
        quit = true;
        return -1;
    }
    //断言，八字节是否转为四字节
    assert(n == sizeof(uint32_t));
    return command;
}

void sendAndWake(pid_t id,int fd,uint32_t command)
{
    //写入命令（系统接口）写入时唤醒了子进程
    write(fd,&command,sizeof(command));
    cout << "main process: call process  " << id << " execute " << desc[command] << " through " << fd << endl;
}

int main()
{
    //把任务加载进函数指针数组里(vector<function<void()>>)
    load();
    //pair<pid，pipefd> 放进程的槽
    vector<pair<pid_t,int>> slots;
    //创建五个子进程
    for(int i = 0;i < PROCESS_NUM;i++)
    {
        //创建管道
        int pipefd[2] = {0}; //pipefd[0] 读  pipefd[1] 写
        int n = pipe(pipefd);
        assert(n != -1);
        //release中断言会被忽略
        (void)n;

        //创建子进程
        pid_t id = fork();
        if(id == 0)
        {
            //子进程 只读 关闭写
            close(pipefd[1]);
            //接收命令 对方不发就阻塞 
            while(true)
            {
                //判断是否退出
                bool quit = false;
                int command = WaitCommand(pipefd[0],quit);
                //收到信息
                if(quit)
                    break;
                if(command >= 0 && command < showSize())
                {
                    //执行
                    callback[command]();
                }
                else{
                    cout << "非法操作:" << command << endl;
                }
            }
            exit(1);
        }   
        //父进程
        close(pipefd[0]);
        //分配一下子进程
        slots.push_back(make_pair(id,pipefd[1]));
    }
    //父进程派发任务
    //搞个随机的 
    srand((unsigned)time(nullptr));
    while(true)
    {
        //选一个随机的任务 
        //int command = rand() % showSize();
        //选一个随机的进程
        int choice = rand() % slots.size();
        //发送消息并唤醒子进程
        showHandler();
        cout << endl;
        int command = 0;
        cout << "input->";
        cin>>command;
        sendAndWake(slots[choice].first,slots[choice].second,command);
        sleep(1);
    }
    //关闭所有子进程
    for(const auto& e:slots)
    {
        close(e.second);
    }

    //回收所有子进程信息
    for(const auto& e:slots)
    {
        waitpid(e.first,nullptr,0);
    }

    return 0;
}